package txtinput

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/streadway/amqp"
)

/*
*  将文件txt输入的内容存入消息队列模块
**/

// TxtProcessor 处理文本文件的结构体
type TxtProcessor struct {
	filePath  string
	queueName string
	mqConn    *amqp.Connection // mq连接
	mqChannel *amqp.Channel    // mq通道
}

// TxtInputConfig 配置选项
type TxtInputConfig struct {
	FilePath  string // 文件夹路径
	QueueName string // 队列名称
	MqURL     string // mq连接地址
}

// 输入消息队列的消息结构体
type TxtInputMessage struct {
	FileName   string    `json:"file_name"` // 一般文件名就是论文ID
	FilePath   string    `json:"file_path"`
	PaperID    string    `json:"paper_id"`
	Content    string    `json:"content"`
	CreateTime time.Time `json:"create_time"`
}

// New 创建新的 TxtProcessor 实例
func New(cfg TxtInputConfig) (*TxtProcessor, error) {
	if cfg.MqURL == "" {
		// 抛出异常
		return nil, fmt.Errorf("输入的mq连接地址为空")
	}

	tp := &TxtProcessor{
		filePath:  cfg.FilePath,
		queueName: cfg.QueueName,
	}

	if err := tp.connect(cfg.MqURL); err != nil {
		return nil, err
	}

	return tp, nil
}

// connect 连接消息队列
func (tp *TxtProcessor) connect(mqURL string) error {
	conn, err := amqp.Dial(mqURL)
	if err != nil {
		return fmt.Errorf("连接消息队列失败: %v", err)
	}

	tp.mqConn = conn

	channel, err := conn.Channel()
	if err != nil {
		return fmt.Errorf("创建通道失败: %v", err)
	}

	tp.mqChannel = channel

	_, err = channel.QueueDeclare(
		tp.queueName,
		true,
		false,
		false,
		false,
		nil,
	)

	return err
}

// Process 处理文件夹下所有文件并发送到消息队列
func (tp *TxtProcessor) Process() error {
	// 检查路径是否存在
	if _, err := os.Stat(tp.filePath); os.IsNotExist(err) {
		return fmt.Errorf("文件夹不存在: %v", err)
	}

	// 遍历文件夹
	return filepath.Walk(tp.filePath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return fmt.Errorf("遍历文件夹错误: %v", err)
		}

		// 跳过文件夹
		if info.IsDir() {
			return nil
		}

		// 可以根据需要添加文件过滤条件
		// 例如: 只处理.txt文件
		if !strings.HasSuffix(path, ".txt") {
			return nil
		}

		content, err := tp.readFileContent(path)
		if err != nil {
			return fmt.Errorf("读取文件 %s 失败: %v", path, err)
		}
		// PaperID 就是 文件名去除后缀
		message := TxtInputMessage{
			FileName:   filepath.Base(path),
			FilePath:   path,
			PaperID:    strings.TrimSuffix(filepath.Base(path), ".txt"),
			Content:    content,
			CreateTime: time.Now(),
		}

		if err := tp.publishMessage(message); err != nil {
			return fmt.Errorf("处理文件 %s 失败: %v", path, err)
		}

		return nil
	})
}

// readFileContent 读取文件内容
func (tp *TxtProcessor) readFileContent(path string) (string, error) {
	file, err := os.Open(path)
	if err != nil {
		return "", fmt.Errorf("打开文件失败: %v", err)
	}
	defer file.Close()

	var content strings.Builder
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		content.WriteString(scanner.Text())
		content.WriteString("\n")
	}

	if err := scanner.Err(); err != nil {
		return "", fmt.Errorf("读取文件内容失败: %v", err)
	}

	return content.String(), nil
}

// publishMessage 发送消息到队列
func (tp *TxtProcessor) publishMessage(message TxtInputMessage) error {
	// 序列化消息为 JSON
	messageBody, err := json.Marshal(message)
	if err != nil {
		return fmt.Errorf("序列化消息失败: %v", err)
	}

	return tp.mqChannel.Publish(
		"",           // exchange
		tp.queueName, // routing key
		false,        // mandatory
		false,        // immediate
		amqp.Publishing{
			ContentType: "application/json",
			Body:        messageBody,
		})
}

// Close 关闭连接
func (tp *TxtProcessor) Close() {
	if tp.mqChannel != nil {
		tp.mqChannel.Close()
	}
	if tp.mqConn != nil {
		tp.mqConn.Close()
	}
}
